package com.hundsun.cprs.yyt.service.quota.service.impl;

import com.hundsun.cprs.yyt.common.base.BaseService;
import com.hundsun.cprs.yyt.common.enums.EnumBusinessCode;
import com.hundsun.cprs.yyt.common.exception.ServiceCodeException;
import com.hundsun.cprs.yyt.common.exception.ServiceException;
import com.hundsun.cprs.yyt.common.redis.RedisDistributedLock;
import com.hundsun.cprs.yyt.service.account.domain.AccountQuotaLog;
import com.hundsun.cprs.yyt.service.account.enums.EnumQuotaTransType;
import com.hundsun.cprs.yyt.service.account.service.AccountQuotaLogService;
import com.hundsun.cprs.yyt.service.common.Constants;
import com.hundsun.cprs.yyt.service.common.dto.UserAccountDTO;
import com.hundsun.cprs.yyt.service.common.service.RemoteUserService;
import com.hundsun.cprs.yyt.service.quota.dao.QuotaDao;
import com.hundsun.cprs.yyt.service.quota.dao.QuotaHoldDao;
import com.hundsun.cprs.yyt.service.quota.domain.QuotaHold;
import com.hundsun.cprs.yyt.service.quota.domain.query.QuotaHoldQuery;
import com.hundsun.cprs.yyt.service.quota.dto.QuotaHoldInfo;
import com.hundsun.cprs.yyt.service.quota.service.QuotaHoldService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.text.MessageFormat;
import java.util.Date;
import java.util.List;

/**
 * 配额持仓相关操作接口
 * @author herong22384
 * @date 2019/8/5 17:31
 */
@Service
public class QuotaHoldServiceImpl extends BaseService implements QuotaHoldService {

    /** 用户配额持仓新增记录锁 */
    public static final String YYT_QUOTE_HOLD_LOCK = Constants.YYT_QUOTE_HOLD_LOCK;

    @Autowired
    private QuotaHoldDao quotaHoldDao;
    @Autowired
    private AccountQuotaLogService quotaLogSerivce;
    @Autowired
    private RemoteUserService remoteUserService;
    @Autowired
    private RedisDistributedLock redisLock;

    @Override
    public void queryByPage(QuotaHoldQuery query) {
        List<QuotaHoldInfo> quoteHoldInfos = quotaHoldDao.queryByPage(query);
        query.compatible(quoteHoldInfos);
    }

    @Override
    @Transactional
    public void deductQuota(Long userId, Long quoteId, Long amount, String operatorType, String memo) {
        int result = quotaHoldDao.updateQuotaAmount(userId,quoteId,amount * -1,0L);
        if (result == 0) {
            logger.error("可用配额不足,扣减失败，userId:" + userId + ",quoteId:" + quoteId);
            throw new ServiceException("可用配额不足,扣减失败");
        }
        //增加配额变更流水
        addQuoteChansLog(userId, quoteId, amount, operatorType, memo);
    }

    @Override
    @Transactional
    public void addQuota(Long userId, Long quoteId, Long amount, String operatorType, String memo) {
        QuotaHoldInfo quotaHold = quotaHoldDao.selectByUserAndQuotaId(userId,quoteId);
        if (quotaHold == null){
            //配额账户不存在，则新增
            createQuoteHoldRecord(userId,quoteId);
        }
        int result = quotaHoldDao.updateQuotaAmount(userId,quoteId,amount,0L);
        if (result == 0) {
            throw new ServiceException("配额账户不存在，增加配额失败，userId:" + userId + ",quoteId:" + quoteId);
        }
        //增加配额变更流水
        addQuoteChansLog(userId, quoteId, amount, operatorType, memo);
    }

    @Override
    @Transactional
    public void freezeQuote(Long userId, Long quoteId, Long amount, String operatorType, String memo) {
        QuotaHoldInfo quotaHold = quotaHoldDao.selectByUserAndQuotaId(userId,quoteId);
        if (quotaHold == null){
            //配额账户不存在，则新增
            createQuoteHoldRecord(userId,quoteId);
        }
        int result = quotaHoldDao.updateQuotaAmount(userId,quoteId,0L,amount);
        if (result == 0) {
            throw new ServiceException("配额账户不存在，冻结配额失败，userId:" + userId + ",quoteId:" + quoteId);
        }
        //增加配额变更流水
        addQuoteChansLog(userId, quoteId, amount, operatorType, memo);
    }

    @Override
    @Transactional
    public void unfreezeQuote(Long userId, Long quoteId, Long amount, String operatorType, String memo) {
        int result = quotaHoldDao.updateQuotaAmount(userId,quoteId,0L,amount * -1);
        if (result == 0) {
            throw new ServiceException("待解冻配额不足,解冻失败，userId:" + userId + ",quoteId:" + quoteId);
        }
        //增加配额变更流水
        addQuoteChansLog(userId, quoteId, amount, operatorType, memo);
    }

    @Override
    public QuotaHoldInfo getQuoteHoldByUserAndQuoteId(Long userId, Long quotaId) {
        return quotaHoldDao.selectByUserAndQuotaId(userId,quotaId);
    }

    protected void addQuoteChansLog(Long userId, Long quotaId, Long amount, String operatorType, String memo){
        if (amount <= 0){
            return;
        }
        QuotaHoldInfo quotaHold = quotaHoldDao.selectByUserAndQuotaId(userId,quotaId);
        AccountQuotaLog log = new AccountQuotaLog();
        log.setQuotaId(quotaId);
        log.setFundAccount(quotaHold.getFundAccount());
        log.setUserId(quotaHold.getUserId());
        log.setTransAmount(new Long(amount));
        log.setTransType(operatorType);
        setAmount(log, quotaHold,operatorType);
        log.setTransDate(new Date());
        log.setMemo(memo);
        quotaLogSerivce.log(log);
    }

    protected void createQuoteHoldRecord(Long userId, Long quotaId){
        String createLockKey = MessageFormat.format(YYT_QUOTE_HOLD_LOCK,userId,quotaId);
        try{
            //获取创建锁,竞争则等待
            if(redisLock.lock(createLockKey)){
                //再次获取配额持仓，存在则返回，不存在则新增
                QuotaHoldInfo hold = quotaHoldDao.selectByUserAndQuotaId(userId,quotaId);
                if (hold != null){
                    return;
                }
                //获取用户详情
                UserAccountDTO userAccountDTO = remoteUserService.getUserDetailByUserId(userId);
                if (userAccountDTO == null){
                    throw new ServiceCodeException(EnumBusinessCode.BUSINESS_1001.getErrorNo(),EnumBusinessCode.BUSINESS_1001.getErrorInfo());
                }
                QuotaHold quotaHold = new QuotaHold();
                quotaHold.setCurrentQuota(0L);
                quotaHold.setFreezeQuota(0L);
                quotaHold.setQuotaId(quotaId);
                quotaHold.setUserId(userId);
                quotaHold.setFundAccount(userAccountDTO.getFundAccount());
                quotaHoldDao.insert(quotaHold);
            }else {
                throw new ServiceCodeException(EnumBusinessCode.BUSINESS_1000.getErrorNo(), "用户配额持仓新增记录锁[" + userId +","+quotaId+ "]");
            }
        }finally {
            redisLock.releaseLock(createLockKey);
        }
    }

    //根据操作类型的不同，设置不同的量，区分冻结量和当前量
    protected void setAmount(AccountQuotaLog log, QuotaHold quotaHold, String operatorType){
        if (operatorType.equals(EnumQuotaTransType.TRANS_0101.getCode()) ||
                operatorType.equals(EnumQuotaTransType.TRANS_0102.getCode()) ||
                operatorType.equals(EnumQuotaTransType.TRANS_0103.getCode())){
            //支出
            log.setPostAmount(quotaHold.getCurrentQuota());
            log.setPreAmount(log.getPostAmount() + log.getTransAmount());
        }else if (operatorType.equals(EnumQuotaTransType.TRANS_0201.getCode()) ||
                operatorType.equals(EnumQuotaTransType.TRANS_0202.getCode())){
            //收入
            log.setPostAmount(quotaHold.getCurrentQuota());
            log.setPreAmount(log.getPostAmount() - log.getTransAmount());
        }else if (operatorType.equals(EnumQuotaTransType.TRANS_0301.getCode()) ||
                operatorType.equals(EnumQuotaTransType.TRANS_0302.getCode())){
            //冻结当前配额量不变
            log.setPostAmount(quotaHold.getCurrentQuota());
            log.setPreAmount(quotaHold.getCurrentQuota());
        }else if (operatorType.equals(EnumQuotaTransType.TRANS_0401.getCode()) ||
                operatorType.equals(EnumQuotaTransType.TRANS_0402.getCode())){
            //解冻当前配额量不变
            log.setPostAmount(quotaHold.getCurrentQuota());
            log.setPreAmount(quotaHold.getCurrentQuota());
        }
    }

	@Override
	public QuotaHoldInfo sumRemainingQuotaByQuery(QuotaHoldQuery query) {
		return quotaHoldDao.sumRemainingQuotaByQuery(query);
	}
    
    
}
